#ifndef TEST_TESTSHORTESTPATH
#define TEST_TESTSHORTESTPATH

#ifdef ECUT_MAIN

#include "cppunit/extensions/HelperMacros.h"
#include "core/Graph.h"
#include "core/path/DijkstraShortestPath.h"
#include "core/path/DistanceCost.h"
#include "core/path/exceptions/OutOfReachException.h"

using namespace path;

class TestShortestPath : public CPPUNIT_NS::TestFixture {
public:
	Graph* searchedGraph;
	DijkstraShortestPath* dijkstra;
	Vertex* vertexA;
	Vertex* vertexB;
	Vertex::Edge* shortEdge;
	Vertex::Edge* longEdge;
	Vertex::Edge* lastEdge;
	void setUp()
	{
		dijkstra = new DijkstraShortestPath(new DistanceCost());
	}
	void tearDown()
	{
		delete searchedGraph;
		delete dijkstra;
	}
	void testTwoVertices()
	{
		testSimpleConfiguration();
		Path* solvedPath;
		try {
			solvedPath = searchedGraph->solvePath(*dijkstra, vertexA, vertexB);
			CPPUNIT_ASSERT_DOUBLES_EQUAL(solvedPath->cost(), 5.1, 0.0001);

			Iterator* iterator = solvedPath->iterator();
			CPPUNIT_ASSERT(iterator->hasNext());
			iterator->next();
			CPPUNIT_ASSERT(iterator->currentVertex()->equals(vertexA));
			CPPUNIT_ASSERT(iterator->transversingEdge()->equals(shortEdge));
			CPPUNIT_ASSERT(iterator->nextVertex()->equals(vertexB));

			delete iterator;
			delete solvedPath;

		} catch (OutOfReachException e) {
			CPPUNIT_FAIL("BUUUUUUH!!");
		}
	}
	void testComplexPathFromWikipedia()
	{
		testComplexConfiguration();
		Path* solvedPath;
		solvedPath = searchedGraph->solvePath(*dijkstra, vertexA, vertexB);
		Iterator* iterator = solvedPath->iterator();
		CPPUNIT_ASSERT(iterator->hasNext());
		iterator->next();
		CPPUNIT_ASSERT(iterator->transversingEdge()->equals(shortEdge));
		CPPUNIT_ASSERT(iterator->hasNext());
		iterator->next();
		CPPUNIT_ASSERT(iterator->transversingEdge()->equals(longEdge));
		CPPUNIT_ASSERT(iterator->hasNext());
		iterator->next();
		CPPUNIT_ASSERT(iterator->transversingEdge()->equals(lastEdge));
	}
	void testUnexistentPath()
	{
		testSimpleConfiguration();
		searchedGraph->solvePath(*dijkstra, vertexB, vertexA);
	}
	CPPUNIT_TEST_SUITE(TestShortestPath);
	CPPUNIT_TEST(testTwoVertices);
	CPPUNIT_TEST(testComplexPathFromWikipedia);

	CPPUNIT_TEST_EXCEPTION(testUnexistentPath, OutOfReachException);
	CPPUNIT_TEST_SUITE_END();
	void testSimpleConfiguration() {
		searchedGraph = new Graph();
		vertexA = searchedGraph->addVertex("a", 1.1, 2.2);
		vertexB = searchedGraph->addVertex("b", 2.2, 1.1);
		Vertex* vertexC = searchedGraph->addVertex("c", 2.2, 1.1);
		longEdge = searchedGraph->addEdge("long", vertexA, vertexB, 10.1, 2.1);
		shortEdge = searchedGraph->addEdge("short", vertexA, vertexB, 5.1, 5.1);
		searchedGraph->addEdge("alt1", vertexA, vertexC, 2.2, 2.2);
		searchedGraph->addEdge("alt2", vertexC, vertexB, 3.3, 3.3);
	}
	void testComplexConfiguration() {
		searchedGraph = new Graph();
		vertexA = searchedGraph->addVertex("a", 1.1, 2.2);
		vertexB = searchedGraph->addVertex("b", 2.2, 1.1);
		Vertex* vertexC = searchedGraph->addVertex("c", 2.2, 1.1);
		Vertex* vertexD = searchedGraph->addVertex("d", 2.2, 1.1);
		Vertex* vertexE = searchedGraph->addVertex("e", 2.2, 1.1);
		Vertex* vertexF = searchedGraph->addVertex("f", 2.2, 1.1);
		searchedGraph->addEdge("a-c", vertexA, vertexC, 14, 2.1);
		shortEdge = searchedGraph->addEdge("a-d", vertexA, vertexD, 9, 5.1);
		searchedGraph->addEdge("a-e", vertexA, vertexE, 7, 5.1);
		searchedGraph->addEdge("c-d", vertexC, vertexD, 2, 2.1);
		lastEdge = searchedGraph->addEdge("c-b", vertexC, vertexB, 9, 2.1);
		longEdge = searchedGraph->addEdge("d-c", vertexD, vertexC, 2, 2.1);
		searchedGraph->addEdge("d-e", vertexD, vertexE, 10, 2.1);
		searchedGraph->addEdge("d-f", vertexD, vertexF, 11, 2.1);
		searchedGraph->addEdge("e-d", vertexE, vertexD, 10, 2.1);
		searchedGraph->addEdge("e-f", vertexE, vertexF, 15, 2.1);
		searchedGraph->addEdge("f-b", vertexF, vertexB, 6, 2.1);
	}
};

#endif /* ECUT_MAIN */

#endif /* TESTSHORTESTPATH */
